package xchange;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;

public class FileInfoParser {

	private BufferedReader in;
	private ArrayList<String> newCreatedFiles = new ArrayList<String>();
	private FileWriter fileWriterForLocalFile;

	/**
	 * Method which generates a command string. The method parses the FileInfo
	 * object. Format of router command:
	 * START-DOWNLOAD<sp><filename><sp><filesize
	 * ><sp><nr_of_blocks><sp><ip><sp><inhoud !info file>
	 * 
	 * @param file
	 *            - FileInfo object
	 * @return String - Router command
	 */
	public String parse(Fileinfo file) {

		String fileInfoString = "START ";

		fileInfoString += file.name + " ";
		fileInfoString += file.size + " ";
		fileInfoString += file.nr_of_blocks + " ";
		fileInfoString += file.ip + " ";

		// Read .!info file
		File infoFile = new File("./info/" + file.name + ".!info");
		// Check if file exists locally
		if (infoFile.exists()) {
			try {
				// Read the .!info file
				FileReader fr = new FileReader(infoFile);
				BufferedReader br = new BufferedReader(fr);
				String str = "";

				while ((str = br.readLine()) != null) {
					fileInfoString += str;
				}

				// in.close();
				// br.close();
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		} else {
			// The download isn't started locally before so create a .!info
			// file.
			Download d = new Download();
			try {
				d.preAllocateFiles(file);
				// Recursive method call after creating .!info file for this
				// download
				parse(file);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		// Return the router command string
		return fileInfoString;
	}

	/**
	 * Method to create a router .!info file on the local harddisk. This file is
	 * being used to compare the local .!info file with the router !.info
	 * 
	 * @param cmd
	 *            String - Representing the result of the router
	 */
	public void createRTInfoFile(String cmd) {

		// message struct:
		// INFO-FILE<sp><filename><sp><filesize><sp><nr_of_blocks><sp><ip><sp><inhoud
		// !info file>

		String[] cmdArr = cmd.split(" ");

		String fileName = cmdArr[1];
		String fileInf = cmdArr[5];

		// Write info to file
		try {
			FileWriter fw = new FileWriter("./info/RT-" + fileName + ".!info");
			BufferedWriter bw = new BufferedWriter(fw);
			bw.write(fileInf);

			// Store new filename temporary in Arraylist
			newCreatedFiles.add(fileName);

			// Close writer
			bw.close();
			fw.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Method that compares router .!info with the local .!info
	 * 
	 * @return HashMap - String representing the filename ArrayList representing
	 *         the blocknumbers which have to be downloaded from the router
	 */
	public HashMap<String, ArrayList<Integer>> compareFileInfoFiles() {

		HashMap<String, ArrayList<Integer>> list = new HashMap<String, ArrayList<Integer>>();

		// Loop the temporary ArrayList of filenames of created router !info
		// files
		for (String filename : newCreatedFiles) {

			// Read .!info file
			File infoFileRT = new File("./info/RT-" + filename + ".!info");
			File infoFileLC = new File("./info/" + filename + ".!info");

			if (infoFileRT.exists() && infoFileLC.exists()) {

				char[] routerChars = generateCharArray(infoFileRT);
				char[] localChars = generateCharArray(infoFileLC);

				if (routerChars.length == localChars.length) {
					ArrayList<Integer> tmp = new ArrayList<Integer>();
					for (int i = 0; i < routerChars.length; i++) {
						if (routerChars[i] == '1' && localChars[i] == '0') {
							tmp.add(i);
						}
					}
					list.put(filename, tmp);
				} else {
					System.err.println("Char size of " + filename
							+ " files does not match");
				}

			} else if (infoFileRT.exists() && infoFileLC.exists() == false) {
				// File only exists on router. Download all the blocks from
				// router
				try {
					// Create local .!infofile
					FileWriter filewriter = new FileWriter(infoFileLC);
					ArrayList<Integer> tmp = new ArrayList<Integer>();

					char[] routerChars = generateCharArray(infoFileRT);

					for (int i = 0; i < routerChars.length; i++) {
						// Check if router has downloaded this block
						if (routerChars[i] == '1') {
							tmp.add(i);
						}
						// Append 0 char to local .!info
						filewriter.append('0');
					}
					list.put(filename, tmp);
				} catch (FileNotFoundException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				}
			} else {
				// No .!info files where found so do nothing.
				System.err.println("File " + filename + " do not match");
			}
		}
		return list;
	}

	/**
	 * Generate a char array representing all the blocks. Format like:
	 * '111111111100000000000'
	 * 
	 * @param file
	 *            .!info file
	 * @return char[] all the chars of the .!info
	 */
	private char[] generateCharArray(File file) {
		try {
			FileInputStream fileStream = new FileInputStream(file);
			DataInputStream in = new DataInputStream(fileStream);
			BufferedReader br = new BufferedReader(new InputStreamReader(in));
			return br.readLine().toCharArray();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}
}
